package com.xiaowen.codeData.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.xiaowen.codeData.dto.*;
import com.xiaowen.codeData.entity.CodeData;
import com.xiaowen.codeData.mapper.CodeDataMapper;
import com.xiaowen.codeData.service.CodeDataService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xiaowen.codeDataRequest.entity.CodeDataRequestParam;
import com.xiaowen.codeDataRequest.service.CodeDataRequestParamService;
import com.xiaowen.dataProcessing.DataProcessingApi;
import com.xiaowen.dataProcessing.dto.*;
import com.xiaowen.projectData.entity.ProjectData;
import com.xiaowen.projectData.service.ProjectDataService;
import com.xiaowen.projectDataCode.entity.ProjectDataCode;
import com.xiaowen.projectDataCode.service.ProjectDataCodeService;
import com.xiaowen.redis.RedisKeys;
import com.xiaowen.redis.RedisUtils;
import com.xiaowen.tool.JsonUtils;
import com.xiaowen.tool.ListUtils;
import com.xiaowen.tool.ObjUtils;
import com.xiaowen.tool.exception.XwException;
import com.xiaowen.tool.excle.ExcelExportDTO;
import com.xiaowen.tool.excle.ExcelTitle;
import com.xiaowen.tool.threadUtil.ThreadPoolExecutorFactory;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.compress.utils.Lists;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.MessageFormat;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.FutureTask;
import java.util.stream.Collectors;

import static com.xiaowen.redis.RedisUtils.NOT_EXPIRE;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author yf-wenhao
 * @since 2024-10-02
 */
@Service
@Slf4j
public class CodeDataServiceImpl extends ServiceImpl<CodeDataMapper, CodeData> implements CodeDataService {

    @Autowired
    private CodeDataMapper codeDataMapper;

    @Autowired
    private ProjectDataService projectDataService;

    @Autowired
    private ProjectDataCodeService projectDataCodeService;

    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    private CodeDataRequestParamService codeDataRequestParamService;

    @Override
    public List<OriginalCodeDTO> generateLabel(Integer projectId) {
        List<OriginalCodeDTO> result = Lists.newArrayList();
        //查询出id/原话数据
        List<ProjectData> projectDataList = projectDataService.queryProjectDataListByProjectId(projectId);
        if (CollectionUtils.isNotEmpty(projectDataList)){
            if (projectDataList.size()>5){
                projectDataList = projectDataList.subList(0,5);
            }
            List<String> index_column = Lists.newArrayList();
            List<String> response_column = Lists.newArrayList();
            for (ProjectData projectData : projectDataList){
                index_column.add(projectData.getIdVal());
                response_column.add(projectData.getOriginalWordVal());
            }
            GenerateLabelReqDTO reqDTO = new GenerateLabelReqDTO();
            reqDTO.setIndex_column(index_column);
            reqDTO.setResponse_column(response_column);
            String request = JsonUtils.toJson(reqDTO);
            Long startTime = System.currentTimeMillis();
            GenerateLabelRespDTO respDTO = DataProcessingApi.generateLabel(reqDTO);
            String response = JsonUtils.toJson(respDTO);
            Long endTime = System.currentTimeMillis();
            buildRequestParam(projectId, DataProcessingApi.GENERATE_LABEL, request, response, ObjUtils.toInteger(endTime-startTime));
            if (ObjectUtil.isNotEmpty(respDTO)){
                List<String> respList = respDTO.getResponse_column();
                List<List<String>> codeList = respDTO.getCode();
                for(int i = 0 ; i < respList.size(); i++){
                    OriginalCodeDTO originalCodeDTO = new OriginalCodeDTO();
                    originalCodeDTO.setOriginal(respList.get(i));
                    originalCodeDTO.setCodeList(codeList.get(i));
                    result.add(originalCodeDTO);
                }
            }
        }
        return result;
    }

    @Override
    public List<CodeData> generateLabelWithExample(OriginalCodeReqDTO reqDTO) {
        List<CodeData> allCodeDataList = Lists.newArrayList();
        List<ProjectData> projectDataList = projectDataService.queryProjectDataListByProjectId(reqDTO.getProjectId());
        if (CollectionUtils.isNotEmpty(projectDataList)) {
            GenerateLabelRespDTO respDTO = null;
            StringBuffer stringBuffer = new StringBuffer();
            for (OriginalCodeDTO originalCodeDTO : reqDTO.getOriginalCodeList()) {
                stringBuffer.append("原话\"").append(originalCodeDTO.getOriginal()).append("\"应标记为").append(JsonUtils.toJson(originalCodeDTO.getCodeList())).append(";");
            }
            String example = stringBuffer.toString();
            List<GenerateLabelRespDTO> respDTOList = new ArrayList<>();
            List<GenerateLabelRespDTO> syncList = Collections.synchronizedList(respDTOList);
            //默认6线程
            int threadCount = 6;
            //大于20再分批处理
            if (projectDataList.size() > 20){
                CountDownLatch latch = new CountDownLatch(threadCount);
                int split = projectDataList.size()/threadCount + 1;
                List<List<ProjectData>> splitList = ListUtils.splitList(projectDataList,split);
                for(List<ProjectData> splitProject : splitList){
                    try {
                        FutureTask<GenerateLabelRespDTO> futureTask = new FutureTask(()->{
                            return getGenerateLabel(reqDTO.getProjectId(), example, splitProject);
                        });
                        ThreadPoolExecutorFactory.getInstance().submit(futureTask);
                        if (ObjUtils.isNotEmpty(futureTask) && ObjUtils.isNotEmpty(futureTask.get())){
                            syncList.add(futureTask.get());
                        }
                    }catch (Exception e){
                        log.info("获取编码错误:{}",e);
                    }finally {
                        latch.countDown();
                    }
                }
                try {
                    latch.await();
                } catch (Exception e) {
                    e.printStackTrace();
                    log.info("结束线程错误");
                }
                if (CollectionUtils.isNotEmpty(syncList)){
                    List<String> columnList = new ArrayList<>();
                    List<List<String>> codeList = new ArrayList<>();
                    for (GenerateLabelRespDTO labelRespDTO : syncList){
                        if (CollectionUtils.isNotEmpty(labelRespDTO.getIndex_column()) && CollectionUtils.isNotEmpty(labelRespDTO.getCode())){
                            columnList.addAll(labelRespDTO.getIndex_column());
                            codeList.addAll(labelRespDTO.getCode());
                        }
                    }
                    respDTO = new GenerateLabelRespDTO();
                    respDTO.setIndex_column(columnList);
                    respDTO.setCode(codeList);
                }
            } else {
                respDTO = getGenerateLabel(reqDTO.getProjectId(), example, projectDataList);
            }
            if (ObjectUtil.isNotEmpty(respDTO) && CollectionUtils.isNotEmpty(respDTO.getCode()) && CollectionUtils.isNotEmpty(respDTO.getIndex_column())) {
                //设置当前项目code从1000开始
                String projectCodeKey = MessageFormat.format(RedisKeys.PROJECT_CODE_KEY, reqDTO.getProjectId());
                redisUtils.set(projectCodeKey, new Integer(1000), NOT_EXPIRE);
                try {
                    int codeListSize = respDTO.getCode().size();
                    //默认101开始
                    List<CodeData> codeDataList = Lists.newArrayList();
                    Date now = new Date();
                    List<ProjectDataCode> projectDataCodeList = Lists.newArrayList();
                    Map<String, Integer> codeNameMap = Maps.newHashMap();
                    Integer sort = 1;
                    for (int i = 0; i < codeListSize; i++){
                        List<String> codeList = respDTO.getCode().get(i);
                        String idVal = respDTO.getIndex_column().get(i);
                        ProjectData projectData = projectDataService.queryByProjectIdAndIdVal(reqDTO.getProjectId(), idVal);
                        for (String codeName : codeList){
                            //去重,处理过直接拿
                            if (codeNameMap.containsKey(codeName)){
                                ProjectDataCode projectDataCode = new ProjectDataCode();
                                projectDataCode.setProjectDataId(projectData.getId());
                                projectDataCode.setCode(codeNameMap.get(codeName));
                                projectDataCode.setName(codeName);
                                projectDataCode.setProjectId(reqDTO.getProjectId());
                                projectDataCode.setCreateTime(now);
                                projectDataCodeList.add(projectDataCode);
                                continue;
                            }
                            int code = getLastCodeByProjectId(reqDTO.getProjectId());
                            codeNameMap.put(codeName, new Integer(code));
                            CodeData codeData = new CodeData();
                            codeData.setCode(code);
                            codeData.setName(codeName);
                            codeData.setProjectId(reqDTO.getProjectId());
                            codeData.setCreateTime(now);
                            codeData.setSort(sort);
                            codeDataList.add(codeData);
                            sort++;
                            if (ObjectUtil.isNotEmpty(projectData)) {
                                ProjectDataCode projectDataCode = new ProjectDataCode();
                                projectDataCode.setProjectDataId(projectData.getId());
                                projectDataCode.setCode(code);
                                projectDataCode.setName(codeName);
                                projectDataCode.setProjectId(reqDTO.getProjectId());
                                projectDataCode.setCreateTime(now);
                                projectDataCodeList.add(projectDataCode);
                            }
                        }
                    }
                    if (CollectionUtils.isNotEmpty(codeDataList)){
                        allCodeDataList.addAll(codeDataList);
                        saveBatch(codeDataList);
                    }
                    if (CollectionUtils.isNotEmpty(projectDataCodeList)){
                        projectDataCodeService.saveBatch(projectDataCodeList);
                    }
                } catch (Exception e){
                    log.info("处理编码数据错误:{}", e);
                }
            }
        }
        return allCodeDataList;
    }

    private GenerateLabelRespDTO getGenerateLabel(Integer projectId, String example, List<ProjectData> projectDataList) {
        List<String> index_column = Lists.newArrayList();
        List<String> response_column = Lists.newArrayList();
        for (ProjectData projectData : projectDataList) {
            index_column.add(projectData.getIdVal());
            response_column.add(projectData.getOriginalWordVal());
        }
        GenerateLabelReqDTO labelReqDTO = new GenerateLabelReqDTO();
        labelReqDTO.setIndex_column(index_column);
        labelReqDTO.setResponse_column(response_column);
        labelReqDTO.setModel(DataProcessingApi.MODEL_DEEPSEEK_CHAT);
        labelReqDTO.setExample(example);

        String request = JsonUtils.toJson(labelReqDTO);
        Long startTime = System.currentTimeMillis();
        GenerateLabelRespDTO respDTO = DataProcessingApi.generateLabelWithExample(labelReqDTO);
        String response = JsonUtils.toJson(respDTO);
        Long endTime = System.currentTimeMillis();
        buildRequestParam(projectId, DataProcessingApi.GENERATE_LABEL_WITH_EXAMPLE, request, response, ObjUtils.toInteger(endTime-startTime));
        return respDTO;
    }

    @Override
    public Integer getLastCodeByProjectId(Integer projectId){
        String projectCodeKey = MessageFormat.format(RedisKeys.PROJECT_CODE_KEY, projectId);
        return redisUtils.incrementInt(projectCodeKey,1);
    }

    @Override
    public Boolean sortCode(CodeDataSortReqDTO sortReqDTO) {
        //
        UpdateWrapper<CodeData> updateWrapper = new UpdateWrapper<>();
        Integer position = sortReqDTO.getPosition();
        CodeData modifyCode = sortReqDTO.getModifyCode();
        CodeData targetCode = sortReqDTO.getTargetCode();
        Integer projectId = modifyCode.getProjectId();
        if (position == -1){
            //最顶级， 查询parentCode为空的数据，整体后移一位,更新移动节点parentCode为null
            updateWrapper.eq("project_id",projectId).isNull("parent_code")
                    .eq("delete_flag",0)
                    .setSql(" `sort` = `sort` + 1");
            codeDataMapper.update(null, updateWrapper);

            modifyCode.setParentCode(null);
            modifyCode.setSort(1);
            codeDataMapper.updateById(modifyCode);

        } else if (position == 0){
            Integer parentCode = targetCode.getCode();
            //子集，更新当前节点parentCode为目标节点code，sort=1 ，更新目标节点下所有子集sort+1
            updateWrapper.eq("project_id",projectId).eq("parent_code",parentCode)
                    .eq("delete_flag",0)
                    .setSql(" `sort` = `sort` + 1");
            codeDataMapper.update(null, updateWrapper);

            modifyCode.setParentCode(parentCode);
            modifyCode.setSort(1);
            codeDataMapper.updateById(modifyCode);

        } else {
            //同级，更新当前节点parentCode为为目标节点parentCode，sort+1，更新目标节点后节点sort+1
            Integer parentCode = targetCode.getParentCode();
            Integer sort = targetCode.getSort();
            //子集，更新当前节点parentCode为目标节点code，sort=1 ，更新目标节点下所有子集sort+1
            updateWrapper.eq("project_id",projectId)
                    .eq("delete_flag",0).gt("sort", sort)
                    .setSql(" `sort` = `sort` + 1");
            if (ObjUtils.isNotEmpty(parentCode)){
                updateWrapper.eq("parent_code",parentCode);
            } else {
                updateWrapper.isNull("parent_code");
            }
            codeDataMapper.update(null, updateWrapper);

            modifyCode.setParentCode(parentCode);
            Integer nextSort = sort++;
            modifyCode.setSort(nextSort);
            codeDataMapper.updateById(modifyCode);
        }
        return null;
    }

    @Override
    public List<CodeData> generateNetName(Integer projectId, Integer code) {
        Integer level = 1;
        List<CodeData> resultList = Lists.newArrayList();
        CodeData codeData = new CodeData();
        codeData.setProjectId(projectId);
        if (ObjectUtil.isNotEmpty(code)){
            level++;
            codeData.setParentCode(code);
        }
        QueryWrapper<CodeData> queryWrapper = new QueryWrapper<>();
        queryWrapper.setEntity(codeData);
        List<CodeData> codeDataList = codeDataMapper.selectList(queryWrapper);
        List<String> codeNameList = Lists.newArrayList();
        if (CollectionUtils.isNotEmpty(codeDataList)){
            if (codeDataList.get(0).getLevel() == 3){
                log.info("当前分层已经为最末级");
                return null;
            }
            codeDataList.forEach(v->{
                codeNameList.add(v.getName());
            });
        }
        GenerateNetReqDTO reqDTO = new GenerateNetReqDTO();
        reqDTO.setCodebook(codeNameList);
        reqDTO.setModel(DataProcessingApi.MODEL_DEEPSEEK);
        String request = JsonUtils.toJson(reqDTO);
        Long startTime = System.currentTimeMillis();
        List<String> netNameList = DataProcessingApi.generateNetName(reqDTO);
        String response = JsonUtils.toJson(netNameList);
        Long endTime = System.currentTimeMillis();
        buildRequestParam(projectId, DataProcessingApi.GENERATE_NET_NAME, request, response, ObjUtils.toInteger(endTime-startTime));
        if (CollectionUtils.isNotEmpty(netNameList)){
            //查询当前项目最高code
            CodeData projectLastData = getLastDataByProjectId(projectId);
            //默认100
            Integer lastCode = 100;
            if (ObjectUtil.isNotEmpty(projectLastData)){
                lastCode = projectLastData.getCode();
            }
            for (String netName : netNameList){
                lastCode++;
                CodeData data = new CodeData();
                data.setCode(lastCode);
                data.setName(netName);
                data.setType(2);
                data.setLevel(level);
                data.setParentCode(code);
                resultList.add(data);
            }
        }
        return resultList;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<CodeData> matchNetName(MatchNetNameReqDTO reqDTO) {
        Integer level = 1;
        CodeData codeData = new CodeData();
        codeData.setProjectId(reqDTO.getProjectId());
        if (ObjectUtil.isNotEmpty(reqDTO.getCode())){
            level++;
            codeData.setParentCode(reqDTO.getCode());
        }
        QueryWrapper<CodeData> queryWrapper = new QueryWrapper<>();
        queryWrapper.setEntity(codeData);
        List<CodeData> codeDataList = codeDataMapper.selectList(queryWrapper);
        List<String> codeNameList = Lists.newArrayList();
        if (CollectionUtils.isNotEmpty(codeDataList)){
            codeDataList.forEach(v->{
                codeNameList.add(v.getName());
            });
        }
        List<String> netNameList = Lists.newArrayList();
        Map<String,Integer> nameCodeMap = Maps.newHashMap();
        //重新生成code，前端code是乱的
        for (CodeData data : reqDTO.getNetList()){
            data.setCode(getLastCodeByProjectId(reqDTO.getProjectId()));
        }
        reqDTO.getNetList().forEach(v->{
            if (ObjUtils.isEmpty(v.getName())){
                throw new XwException(500,"编码名称不能为空");
            }
            netNameList.add(v.getName());
            nameCodeMap.put(v.getName(),v.getCode());
        });
        GenerateNetReqDTO netReqDTO = new GenerateNetReqDTO();
        netReqDTO.setCodebook(codeNameList);
        netReqDTO.setModel(DataProcessingApi.MODEL_DEEPSEEK);
        netReqDTO.setNet_name_list(netNameList);
        String request = JsonUtils.toJson(netReqDTO);
        Long startTime = System.currentTimeMillis();
        List<MatchNetNameRespDTO> nameRespDTOList = DataProcessingApi.matchNetName(netReqDTO);
        String response = JsonUtils.toJson(nameRespDTOList);
        Long endTime = System.currentTimeMillis();
        buildRequestParam(reqDTO.getProjectId(), DataProcessingApi.MATCH_NET_NAME, request, response, ObjUtils.toInteger(endTime-startTime));
        if (CollectionUtils.isNotEmpty(nameRespDTOList)){
            Date now = new Date();
            //添加数据
            for (CodeData data : reqDTO.getNetList()){
                data.setProjectId(reqDTO.getProjectId());
                data.setCreateTime(now);
                data.setParentCode(reqDTO.getCode());
                data.setLevel(level);
                // codeDataMapper.insert(v);
            }
            saveBatch(reqDTO.getNetList());

            Map<String, String> nameLabelMap = nameRespDTOList.stream().collect(Collectors.toMap(MatchNetNameRespDTO::getName, MatchNetNameRespDTO::getLabel, (s1, s2) -> s1));
            //下降等级
            level++;
            //更新
            for (CodeData data : codeDataList){
                String labelName = nameLabelMap.get(data.getName());
                if (ObjectUtil.isNotEmpty(labelName)){
                    log.info("分层:{}",labelName);
                    Integer parentCode = nameCodeMap.get(labelName);
                    if (ObjectUtil.isNotEmpty(parentCode)){
                        data.setParentCode(parentCode);
                        data.setLevel(level);
                        data.setUpdateTime(now);
                        codeDataMapper.updateById(data);
                    }
                }
            }
        }
        return null;
    }

    @Override
    public List<CodeDataDTO> listByProjectId(Integer projectId, Integer code) {
        CodeData codeData = new CodeData();
        codeData.setProjectId(projectId);
        codeData.setDeleteFlag(false);
        if (ObjectUtil.isNotEmpty(code)){
            codeData.setParentCode(code);
        }
        QueryWrapper<CodeData> queryWrapper = new QueryWrapper<>();
        queryWrapper.setEntity(codeData);
        queryWrapper.orderByAsc("sort");
        List<CodeData> codeDataList = codeDataMapper.selectList(queryWrapper);
        if (CollectionUtils.isNotEmpty(codeDataList)){
            List<CodeDataDTO> codeDataDTOList = JsonUtils.toCollectionBean(JsonUtils.toJson(codeDataList), List.class, CodeDataDTO.class);
            Map<Integer, CodeDataDTO> nodeMap = Maps.newHashMap();
            for (CodeDataDTO dataDTO : codeDataDTOList) {
                nodeMap.put(dataDTO.getCode(), dataDTO);
            }
            List<CodeDataDTO> tree = Lists.newArrayList();
            for (CodeDataDTO dto : codeDataDTOList) {
                // 如果没有父节点，则是根节点
                if (dto.getParentCode() == null) {
                    dto.setLevel(1);
                    tree.add(dto);
                } else {
                    // 找到父节点并将当前节点添加到父节点的子列表中
                    CodeDataDTO parent = nodeMap.get(dto.getParentCode());
                    if (parent != null) {
                        Integer level = parent.getLevel();
                        Integer nextLevel = level+1;
                        dto.setLevel(nextLevel);
                        parent.getChildren().add(dto);
                    }
                }
            }
            return tree;
        }
        return null;
    }

    @Override
    public Boolean add(CodeData codeData) {
        codeData.setCode(getLastCodeByProjectId(codeData.getProjectId()));
        codeData.setCreateTime(new Date());
        //处理父code
        handleParentCode(codeData);
        int size = codeDataMapper.insert(codeData);
        if (size > 0){
            return true;
        }
        return false;
    }

    private void handleParentCode(CodeData codeData) {
        if (ObjUtils.isNotEmpty(codeData.getParentCode())){
            //需判断当前父节点是否为有子节点，若无，那么变更为net节点，需删除左侧码表数据
            List<CodeData> codeDataList = getByParentCode(codeData.getProjectId(), codeData.getParentCode());
            if (CollectionUtils.isEmpty(codeDataList)){
                log.info("当前父级无子集，需新增net节点");
                //1 新增net节点 2 更新当前两个节点的parentCode
                CodeData parentCodeData = getByCode(codeData.getProjectId(), codeData.getParentCode());
                CodeData codeDataNet = new CodeData();
                BeanUtils.copyProperties(parentCodeData, codeDataNet);
                codeDataNet.setCode(getLastCodeByProjectId(codeData.getProjectId()));
                codeDataNet.setId(null);
                codeDataNet.setCreateTime(new Date());
                codeDataNet.setType(2);
                codeDataMapper.insert(codeDataNet);
                parentCodeData.setParentCode(codeDataNet.getCode());
                codeData.setParentCode(codeDataNet.getCode());
                codeDataMapper.updateById(parentCodeData);
            }
        }
    }

    private List<CodeData> getByParentCode(Integer projectId, Integer parentCode) {
        CodeData codeData = new CodeData();
        codeData.setProjectId(projectId);
        codeData.setDeleteFlag(false);
        codeData.setParentCode(parentCode);
        QueryWrapper<CodeData> queryWrapper = new QueryWrapper<>();
        queryWrapper.setEntity(codeData);
        return codeDataMapper.selectList(queryWrapper);
    }

    private CodeData getByCode(Integer projectId, Integer code) {
        CodeData codeData = new CodeData();
        codeData.setProjectId(projectId);
        codeData.setDeleteFlag(false);
        codeData.setCode(code);
        QueryWrapper<CodeData> queryWrapper = new QueryWrapper<>();
        queryWrapper.setEntity(codeData);
        return codeDataMapper.selectList(queryWrapper).get(0);
    }

    @Override
    public List<List<CodeData>> similarCombine(MatchNetNameReqDTO reqDTO) {
        CodeData codeData = new CodeData();
        codeData.setProjectId(reqDTO.getProjectId());
        if (ObjectUtil.isNotEmpty(reqDTO.getCode())){
            codeData.setParentCode(reqDTO.getCode());
        }
        QueryWrapper<CodeData> queryWrapper = new QueryWrapper<>();
        queryWrapper.setEntity(codeData);
        List<CodeData> codeDataList = codeDataMapper.selectList(queryWrapper);
        if (CollectionUtils.isNotEmpty(codeDataList)){
            List<Map> mapList = codeDataList.stream().map(v->{
                Map<String, String> map = Maps.newHashMap();
                map.put(ObjectUtil.toString(v.getCode()), v.getName());
                return map;
            }).collect(Collectors.toList());
            SimilarCombineReqDTO combineReqDTO = new SimilarCombineReqDTO();
            combineReqDTO.setMatch_label_list(mapList);
            String request = JsonUtils.toJson(combineReqDTO);
            Long startTime = System.currentTimeMillis();
            List<SimilarCombineRespDTO> respDTOList = DataProcessingApi.similarCombine(combineReqDTO);
            String response = JsonUtils.toJson(respDTOList);
            Long endTime = System.currentTimeMillis();
            buildRequestParam(reqDTO.getProjectId(), DataProcessingApi.SIMILAR_COMBINE, request, response, ObjUtils.toInteger(endTime-startTime));
            if (CollectionUtils.isNotEmpty(respDTOList)){
                Map<String,List<CodeData>> combineMap = Maps.newHashMap();
                for (SimilarCombineRespDTO respDTO : respDTOList){
                    List<CodeData> codeList = combineMap.get(respDTO.getOutput());
                    Map<String, String> label = respDTO.getLabel();
                    if (CollectionUtils.isEmpty(codeList)){
                        codeList = Lists.newArrayList();
                        combineMap.put(respDTO.getOutput(), codeList);
                    }
                    if (ObjUtils.isNotEmpty(label)){
                        CodeData data = new CodeData();
                        label.forEach((k,v)->{
                            data.setCode(ObjUtils.toInteger(k));
                            data.setName(v);
                        });
                        codeList.add(data);
                    }
                }
                return new ArrayList<>(combineMap.values());
            }
        }
        return null;
    }

    @Override
    public Boolean confirmCombine(ConfirmCombineDTO combineDTO){
        List<List<CodeData>> respDTOList = combineDTO.getCombineList();
        Integer projectId = combineDTO.getProjectId();
        if (CollectionUtils.isNotEmpty(respDTOList)){
            Map<String,List<Integer>> combineMap = Maps.newHashMap();
            for (List<CodeData> dataList : respDTOList){
                List<String> nameList = Lists.newArrayList();
                List<Integer> codeList = Lists.newArrayList();
                dataList.forEach(v->{
                    nameList.add(v.getName());
                    codeList.add(v.getCode());
                });
                String nameKey = StringUtils.join(nameList,"/");
                combineMap.put(nameKey, codeList);
            }
            //todo合并
            handleCombineMap(combineMap, projectId);
        }
        return true;
    }

    @Override
    public ExcelExportDTO getCodeExcelExportDTO(Integer projectId) {
        List<CodeDataDTO> codeDataDTOList = listByProjectId(projectId,null);
        if (CollectionUtils.isEmpty(codeDataDTOList)){
            return null;
        }
        List<ExcelTitle> excelTitleList = Lists.newArrayList();
        excelTitleList.add(new ExcelTitle("码表编码"));
        excelTitleList.add(new ExcelTitle("码表名称"));
        List<Map<String, Object>> dataList = Lists.newArrayList();
        //处理数据
        handleExportCodeData(codeDataDTOList, dataList,"Net");

        ExcelExportDTO excelExportDTO = new ExcelExportDTO();
        excelExportDTO.setTitleAry(excelTitleList);
        excelExportDTO.setDataList(dataList);
        return excelExportDTO;
    }

    private void handleExportCodeData(List<CodeDataDTO> codeDataDTOList, List<Map<String, Object>> dataList, String netName){
        codeDataDTOList.forEach(codeDataDTO -> {
            if (CollectionUtils.isNotEmpty(codeDataDTO.getChildren())){
                Map<String, Object> dataMap = Maps.newHashMap();
                dataMap.put("码表编码", null);
                dataMap.put("码表名称", netName+" "+codeDataDTO.getName());
                dataList.add(dataMap);
                handleExportCodeData(codeDataDTO.getChildren(), dataList, "sub"+netName);
            }else {
                //没有子集，那么直接添加
                Map<String, Object> dataMap = Maps.newHashMap();
                dataMap.put("码表编码", codeDataDTO.getCode());
                dataMap.put("码表名称", codeDataDTO.getName());
                dataList.add(dataMap);
            }
        });
    }


    @Override
    public Boolean combineByChoose(MatchNetNameReqDTO reqDTO) {
        List<String> nameList = Lists.newArrayList();
        List<Integer> codeList = Lists.newArrayList();
        reqDTO.getNetList().forEach(codeData -> {
            nameList.add(codeData.getName());
            codeList.add(codeData.getCode());
        });
        String combineName = StringUtils.join(nameList,"/");
        Map<String, List<Integer>> combineMap = Maps.newHashMap();
        combineMap.put(combineName, codeList);

        handleCombineMap(combineMap, reqDTO.getProjectId());
        return true;
    }

    @Override
    public Boolean update(CodeData codeData) {
        //先更新左侧，再更新code
        projectDataCodeService.updateByCode(codeData);
        //处理父code
        handleParentCode(codeData);
        codeDataMapper.updateById(codeData);
        return true;
    }

    private void handleCombineMap(Map<String,List<Integer>> combineMap, Integer projectId){
        List<ProjectDataCode> dataCodeList = Lists.newArrayList();
        combineMap.forEach((k,v)->{
            //只处理1以上
            if (CollectionUtils.isNotEmpty(v) && v.size() > 1){
                Integer finalCode = v.get(0);
                String finalName = k;
                Date now = new Date();
                List<ProjectDataCode> projectDataCodeList = projectDataCodeService.queryDataCodeByCode(projectId, v);
                //处理数据关联编码数据
                if (CollectionUtils.isNotEmpty(projectDataCodeList)){
                    List<Integer> idList = Lists.newArrayList();
                    Set<Integer> dataIdSet = Sets.newHashSet();
                    projectDataCodeList.forEach(projectDataCode -> {
                        idList.add(projectDataCode.getId());
                        dataIdSet.add(projectDataCode.getProjectDataId());
                    });
                    //删除历史
                    projectDataCodeService.deleteByIds(idList);
                    //循环新增合并后数据
                    for (Integer dataId : dataIdSet){
                        ProjectDataCode projectDataCode = new ProjectDataCode();
                        projectDataCode.setCode(finalCode);
                        projectDataCode.setProjectId(projectId);
                        projectDataCode.setName(finalName);
                        projectDataCode.setProjectDataId(dataId);
                        projectDataCode.setCreateTime(now);
                        dataCodeList.add(projectDataCode);
                    }
                }
                //更新名称
                updateNameByCode(finalName, finalCode, projectId);
                //去除
                v.remove(finalCode);
                //处理编码数据
                deleteByCodes(projectId, v);
            }
        });
        if (CollectionUtils.isNotEmpty(dataCodeList)){
            projectDataCodeService.saveBatch(dataCodeList);
        }
    }

    private void updateNameByCode(String finalName, Integer finalCode, Integer projectId) {
        CodeData entity = new CodeData();
        entity.setDeleteFlag(false);
        entity.setUpdateTime(new Date());
        entity.setName(finalName);
        CodeData codeData = new CodeData();
        codeData.setProjectId(projectId);
        codeData.setCode(finalCode);
        codeData.setDeleteFlag(false);
        QueryWrapper<CodeData> queryWrapper = new QueryWrapper<>();
        queryWrapper.setEntity(codeData);
        codeDataMapper.update(entity, queryWrapper);
    }

    private void deleteByCodes(Integer projectId, List<Integer> codeList){
        CodeData entity = new CodeData();
        entity.setDeleteFlag(true);
        entity.setUpdateTime(new Date());
        CodeData codeData = new CodeData();
        codeData.setProjectId(projectId);
        QueryWrapper<CodeData> queryWrapper = new QueryWrapper<>();
        queryWrapper.setEntity(codeData);
        queryWrapper.in("code", codeList);
        codeDataMapper.update(entity, queryWrapper);
    }

    private CodeData getLastDataByProjectId(Integer projectId){
        CodeData codeData = new CodeData();
        codeData.setProjectId(projectId);
        QueryWrapper<CodeData> queryWrapper = new QueryWrapper<>();
        queryWrapper.setEntity(codeData);
        queryWrapper.orderByDesc("id");
        queryWrapper.last("LIMIT 1");
        List<CodeData> codeDataList = codeDataMapper.selectList(queryWrapper);
        if (CollectionUtils.isNotEmpty(codeDataList)){
            return codeDataList.get(0);
        }
        return null;
    }

    private void buildRequestParam(Integer projectId, String requestName, String request, String response, Integer costTime){
        try {
            CodeDataRequestParam codeDataRequestParam = new CodeDataRequestParam();
            codeDataRequestParam.setProjectId(projectId);
            codeDataRequestParam.setName(requestName);
            codeDataRequestParam.setRequest(request);
            codeDataRequestParam.setResponse(response);
            codeDataRequestParam.setCostTime(costTime);
            codeDataRequestParam.setCreateTime(new Date());
            codeDataRequestParamService.save(codeDataRequestParam);
        } catch (Exception e){
            log.info("添加操作记录失败:{}", e);
        }
    }
}
